#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "esp_log.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"
#include "freertos/timers.h"
#include "driver/gpio.h"
#include "device.h"
#include "factory_time.h"
#include "factory_config.h"

const static char *TAG = "device";

#define BTN_DEBOUNCE_TIME_MS 50
#define TIMER_PERIOD                200
esp_timer_handle_t TIMER;
// TimerHandle_t buttun_timer;


#define DEV_OK      0
#define DEV_ERR     -1




struct _led_state led_state[4] = {
    { LED_OFF, WIFI_INDICATOR_LED, "wifi indicator" },
    { LED_OFF, BLE_INDICATOR_LED,  "ble  indicator" },
    { LED_OFF, WORK_INDICATOR_LED, "work indicator" },
    { LED_OFF, INTERNET_INDICATOR_LED, "internet indicator" },
};

void led_operation(uint8_t pin, uint8_t onoff)
{
    for (int i = 0; i < sizeof(led_state); i++) {
        if (led_state[i].pin != pin) {
            continue;
        }

        if (onoff == led_state[i].previous) {
            ESP_LOGI(TAG, "led %s is already %s",led_state[i].name, (onoff ? "on" : "off"));
            return;
        }

        
        gpio_set_level(pin, onoff);
        led_state[i].previous = onoff;
        return;
    }
    ESP_LOGE(TAG, "LED is not found!");
}


void led_init(void)
{
    gpio_config_t io_conf;

    io_conf.intr_type = GPIO_INTR_DISABLE;
    io_conf.pin_bit_mask = ((1ULL << WORK_INDICATOR_LED) | (1ULL << INTERNET_INDICATOR_LED) | (1ULL << BLE_INDICATOR_LED) | (1ULL << WIFI_INDICATOR_LED));
    // io_conf.pin_bit_mask  = (1ULL << INTERNET_INDICATOR_LED);
    io_conf.mode = GPIO_MODE_OUTPUT;
    io_conf.pull_down_en = GPIO_PULLDOWN_DISABLE;
    io_conf.pull_up_en = GPIO_PULLUP_DISABLE;
    
    gpio_config(&io_conf);
    gpio_set_level(WORK_INDICATOR_LED, LED_OFF);
    gpio_set_level(INTERNET_INDICATOR_LED, LED_OFF);
    gpio_set_level(BLE_INDICATOR_LED, LED_OFF);
    gpio_set_level(WIFI_INDICATOR_LED, LED_OFF);
}



static void key_init(uint32_t key_gpio)
{
    gpio_config_t io_conf;

    //interrupt of rising edge
    io_conf.intr_type = GPIO_INTR_ANYEDGE;  //上升沿、下降沿触发
    //bit mask of the pins, use GPIO4/5 here
    io_conf.pin_bit_mask = (1ULL << key_gpio);
    //set as input mode    
    io_conf.mode = GPIO_MODE_INPUT;
    //enable pull-up mode
    io_conf.pull_up_en = 1;
    gpio_config(&io_conf);

    gpio_install_isr_service(0);
    //change gpio intrrupt type for one pin
    gpio_set_intr_type(GPIO_INPUT_KEY, GPIO_INTR_ANYEDGE);  
}


int count = 0;
static void key_handler_call(BTN_TYPE_E type)
{
    switch(type)
    {
        case NORMAL_BTN:    //短按事件
        case LONG_BTN:      //长按事件
            printf("boot_ctn\r\n");   
            if(count%2 == 0){
                led_operation(WIFI_INDICATOR_LED, LED_ON);
                led_operation(BLE_INDICATOR_LED, LED_ON);
                led_operation(INTERNET_INDICATOR_LED, LED_ON);
                led_operation(WORK_INDICATOR_LED, LED_ON);
            }
            else{
                led_operation(WIFI_INDICATOR_LED, LED_OFF);
                led_operation(BLE_INDICATOR_LED, LED_OFF);
                led_operation(INTERNET_INDICATOR_LED, LED_OFF);
                led_operation(WORK_INDICATOR_LED, LED_OFF);
            }
            count++;
            break;
        default : 
            break;
    }

}


/****************** 按键按下事件处理函数 ******************/
static void key_press_handler(key_handle_t *handle)
{
    //激活长按定时器开始计时
    arch_os_timer_activate(handle->long_key_timer);
	return;
}


/* 按键松开事件处理函数 */
static void key_release_handler(key_handle_t *handle)
{
    esp_timer_stop(TIMER);
    // 	长按键定时器没超时，则作为普通按键处理，关闭长按键定时器
    if (DEV_OK == arch_os_timer_is_active(handle->long_key_timer)){
        arch_os_timer_deactivate(handle->long_key_timer);
        handle->call_back(NORMAL_BTN);
    }
    else {  //长按超时，等待松开
        if (NULL != handle->call_back){
            handle->call_back(LONG_BTN);
        }
    }
}




/* ******************************
* 按键事件处理函数
**********************************/
static void __key_event_handler(key_handle_t *handler, int gpio_level)
{
    int press = 0;
    //按键按下
    if(handler->start_gpio_level != gpio_level){
        press = 1;
    }

    if(press == 1){
        key_press_handler(handler);     //按下处理事件
    } else {
        key_release_handler(handler);   //松开处理事件
    }
}



static void _key_check(TimerHandle_t timer)
{
    key_handle_t *handler = (key_handle_t *)arch_os_timer_get_context(timer);
    int gpio_level = gpio_get_level(handler->gpio_no);
    //消抖成功
    if(gpio_level != handler->gpio_level){
        __key_event_handler(handler, gpio_level);
        handler->gpio_level = gpio_level;
    }
}



static void led_flash(void *parm){

}

static void _key_long_handler(TimerHandle_t timer)
{

}


//中断处理
static void key_isr_handler(void *key_handle)
{
    key_handle_t *handle = key_handle;
    TimerHandle_t debounce_timer = handle->buttun_timer;
    /* 检查计时器活动状态 */
    if (DEV_OK == arch_os_timer_is_active(debounce_timer)) {
        arch_os_timer_deactivate(debounce_timer);
    }

    /* 更改计时器时间多久后到期 */
    arch_os_timer_change(debounce_timer, BTN_DEBOUNCE_TIME_MS);
    if (DEV_OK != arch_os_timer_activate(debounce_timer)) {
        ESP_LOGE(TAG, "active debounce timer fail\r\n");
    }
    return;
}


void key_handler_init(void)
{
    key_handle_t *handler = (key_handle_t *)malloc(sizeof(key_handle_t));
    if(handler != NULL){
        
        handler->gpio_no = GPIO_INPUT_KEY;
        handler->long_time = 3 * 1000;  //恢复出产设置长按时间定时器
        handler->call_back = key_handler_call;

        key_init(handler->gpio_no);

        handler->start_gpio_level = gpio_get_level(handler->gpio_no);
        handler->gpio_level = handler->start_gpio_level;
        if(DEV_OK != arch_os_timer_create(&handler->buttun_timer, "buttun_timer",BTN_DEBOUNCE_TIME_MS, _key_check,
                handler, ARCH_OS_TIMER_ONE_SHOT, ARCH_OS_TIMER_NO_ACTIVATE))
        {
            ESP_LOGE(TAG,"create button [%d] long button timer fail!\r\n",handler->gpio_no);
            free(handler);
            handler = NULL; 
        }

        /* 长按 */
        if(DEV_OK != arch_os_timer_create(&handler->long_key_timer, "long_key_timer", handler->long_time,_key_long_handler,
            handler, ARCH_OS_TIMER_ONE_SHOT, ARCH_OS_TIMER_NO_ACTIVATE))
        {
            ESP_LOGE(TAG,"create button [%d] long button timer fail!\r\n",handler->gpio_no);
            free(handler);
            handler = NULL;   
        }

        gpio_isr_handler_add(handler->gpio_no, key_isr_handler, handler); 
    }    

}
